import sys
import os
import cv2
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                             QHBoxLayout, QLabel, QPushButton, QFileDialog,
                             QSlider, QComboBox, QMenuBar, QToolBar, QStatusBar,
                             QDockWidget, QGroupBox, QFormLayout, QLineEdit,
                             QSplitter, QMessageBox, QTabWidget)
from PyQt5.QtGui import QImage, QPixmap, QIcon
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal


class CVPlatform(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.image = None
        self.processed_image = None
        self.video_capture = None
        self.is_video_playing = False
        self.face_db = {}  # 人脸数据库
        self.init_face_db()

    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle("计算机视觉应用开发平台")
        self.setGeometry(100, 100, 1200, 800)

        # 创建菜单栏
        self.create_menu_bar()

        # 创建工具栏
        self.create_tool_bar()

        # 创建主布局
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.main_layout = QHBoxLayout(self.central_widget)

        # 创建左侧控制面板
        self.control_panel = QDockWidget("控制面板", self)
        self.control_panel.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.control_widget = QWidget()
        self.control_layout = QVBoxLayout(self.control_widget)
        self.control_panel.setWidget(self.control_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.control_panel)

        # 创建右侧结果显示面板
        self.result_panel = QDockWidget("结果显示", self)
        self.result_panel.setAllowedAreas(Qt.RightDockWidgetArea)
        self.result_widget = QWidget()
        self.result_layout = QVBoxLayout(self.result_widget)
        self.result_panel.setWidget(self.result_widget)
        self.addDockWidget(Qt.RightDockWidgetArea, self.result_panel)

        # 创建图像/视频显示区域
        self.display_widget = QLabel("请加载图像或视频")
        self.display_widget.setAlignment(Qt.AlignCenter)
        self.display_widget.setMinimumSize(640, 480)
        self.display_widget.setStyleSheet("border: 1px solid #cccccc;")
        self.main_layout.addWidget(self.display_widget)

        # 创建参数设置区域
        self.create_parameter_settings()

        # 创建状态栏
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        self.statusBar.showMessage("就绪")

        # 创建计时器用于视频播放
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_frame)

    def create_menu_bar(self):
        """创建菜单栏"""
        menubar = self.menuBar()

        # 文件菜单
        file_menu = menubar.addMenu("文件")

        open_image_action = file_menu.addAction("打开图像")
        open_image_action.triggered.connect(self.open_image)

        open_video_action = file_menu.addAction("打开视频")
        open_video_action.triggered.connect(self.open_video)

        open_camera_action = file_menu.addAction("打开摄像头")
        open_camera_action.triggered.connect(self.open_camera)

        file_menu.addSeparator()

        save_action = file_menu.addAction("保存结果")
        save_action.triggered.connect(self.save_result)

        file_menu.addSeparator()

        exit_action = file_menu.addAction("退出")
        exit_action.triggered.connect(self.close)

        # 编辑菜单
        edit_menu = menubar.addMenu("编辑")

        rotate_action = edit_menu.addAction("旋转")
        rotate_action.triggered.connect(self.rotate_image)

        scale_action = edit_menu.addAction("缩放")
        scale_action.triggered.connect(self.scale_image)

        crop_action = edit_menu.addAction("裁剪")
        crop_action.triggered.connect(self.crop_image)

        # 处理菜单
        process_menu = menubar.addMenu("处理")

        color_adjust_action = process_menu.addAction("色彩调整")
        color_adjust_action.triggered.connect(self.adjust_color)

        smooth_action = process_menu.addAction("平滑处理")
        smooth_action.triggered.connect(self.smooth_image)

        shape_detection_action = process_menu.addAction("形状识别")
        shape_detection_action.triggered.connect(self.detect_shapes)

        face_detection_action = process_menu.addAction("人脸检测")
        face_detection_action.triggered.connect(self.detect_faces)

        face_recognition_action = process_menu.addAction("人脸识别")
        face_recognition_action.triggered.connect(self.recognize_faces)

        image_stitching_action = process_menu.addAction("图像拼接")
        image_stitching_action.triggered.connect(self.stitch_images)

        # 帮助菜单
        help_menu = menubar.addMenu("帮助")

        about_action = help_menu.addAction("关于")
        about_action.triggered.connect(self.show_about)

    def create_tool_bar(self):
        """创建工具栏"""
        toolbar = QToolBar("主工具栏")
        self.addToolBar(toolbar)

        open_image_action = toolbar.addAction(QIcon.fromTheme("document-open"), "打开图像")
        open_image_action.triggered.connect(self.open_image)

        open_video_action = toolbar.addAction(QIcon.fromTheme("media-playback-start"), "打开视频")
        open_video_action.triggered.connect(self.open_video)

        open_camera_action = toolbar.addAction(QIcon.fromTheme("camera-web"), "打开摄像头")
        open_camera_action.triggered.connect(self.open_camera)

        toolbar.addSeparator()

        save_action = toolbar.addAction(QIcon.fromTheme("document-save"), "保存结果")
        save_action.triggered.connect(self.save_result)

        toolbar.addSeparator()

        play_action = toolbar.addAction(QIcon.fromTheme("media-playback-start"), "播放")
        play_action.triggered.connect(self.play_video)

        pause_action = toolbar.addAction(QIcon.fromTheme("media-playback-pause"), "暂停")
        pause_action.triggered.connect(self.pause_video)

        stop_action = toolbar.addAction(QIcon.fromTheme("media-playback-stop"), "停止")
        stop_action.triggered.connect(self.stop_video)

        toolbar.addSeparator()

        previous_action = toolbar.addAction(QIcon.fromTheme("media-skip-backward"), "上一帧")
        previous_action.triggered.connect(self.previous_frame)

        next_action = toolbar.addAction(QIcon.fromTheme("media-skip-forward"), "下一帧")
        next_action.triggered.connect(self.next_frame)

    def create_parameter_settings(self):
        """创建参数设置区域"""
        self.param_tabs = QTabWidget()
        self.control_layout.addWidget(self.param_tabs)

        # 图像处理参数
        image_params = QWidget()
        image_layout = QFormLayout(image_params)

        self.brightness_slider = QSlider(Qt.Horizontal)
        self.brightness_slider.setRange(-100, 100)
        self.brightness_slider.setValue(0)
        self.brightness_slider.valueChanged.connect(self.update_image_parameters)
        image_layout.addRow("亮度:", self.brightness_slider)

        self.contrast_slider = QSlider(Qt.Horizontal)
        self.contrast_slider.setRange(-100, 100)
        self.contrast_slider.setValue(0)
        self.contrast_slider.valueChanged.connect(self.update_image_parameters)
        image_layout.addRow("对比度:", self.contrast_slider)

        self.saturation_slider = QSlider(Qt.Horizontal)
        self.saturation_slider.setRange(-100, 100)
        self.saturation_slider.setValue(0)
        self.saturation_slider.valueChanged.connect(self.update_image_parameters)
        image_layout.addRow("饱和度:", self.saturation_slider)

        self.param_tabs.addTab(image_params, "图像处理")

        # 人脸识别参数
        face_params = QWidget()
        face_layout = QFormLayout(face_params)

        self.confidence_threshold = QSlider(Qt.Horizontal)
        self.confidence_threshold.setRange(0, 100)
        self.confidence_threshold.setValue(70)
        self.confidence_threshold.valueChanged.connect(self.update_face_parameters)
        face_layout.addRow("识别阈值:", self.confidence_threshold)

        self.param_tabs.addTab(face_params, "人脸识别")

        # 形状识别参数
        shape_params = QWidget()
        shape_layout = QFormLayout(shape_params)

        self.shape_threshold = QSlider(Qt.Horizontal)
        self.shape_threshold.setRange(0, 255)
        self.shape_threshold.setValue(128)
        self.shape_threshold.valueChanged.connect(self.update_shape_parameters)
        shape_layout.addRow("阈值:", self.shape_threshold)

        self.param_tabs.addTab(shape_params, "形状识别")

    def init_face_db(self):
        """初始化人脸数据库"""
        # 这里可以加载预训练的人脸模型和人脸数据
        # 实际应用中可能需要从文件或数据库加载
        self.face_db = {
            "person1": cv2.imread("faces/person1.jpg"),
            "person2": cv2.imread("faces/person2.jpg"),
            # 添加更多人脸数据...
        }

    def open_image(self):
        """打开图像文件"""
        file_path, _ = QFileDialog.getOpenFileName(self, "打开图像", "",
                                                   "图像文件 (*.png *.jpg *.jpeg *.bmp *.gif)")
        if file_path:
            self.image = cv2.imread(file_path)
            self.processed_image = self.image.copy()
            self.display_image(self.processed_image)
            self.statusBar.showMessage(f"已加载图像: {os.path.basename(file_path)}")

    def open_video(self):
        """打开视频文件"""
        file_path, _ = QFileDialog.getOpenFileName(self, "打开视频", "",
                                                   "视频文件 (*.mp4 *.avi *.mov *.mkv)")
        if file_path:
            self.video_capture = cv2.VideoCapture(file_path)
            if self.video_capture.isOpened():
                self.is_video_playing = True
                self.timer.start(30)  # 约33fps
                self.statusBar.showMessage(f"已加载视频: {os.path.basename(file_path)}")
            else:
                QMessageBox.warning(self, "错误", "无法打开视频文件")

    def open_camera(self):
        """打开摄像头"""
        self.video_capture = cv2.VideoCapture(0)  # 0表示默认摄像头
        if self.video_capture.isOpened():
            self.is_video_playing = True
            self.timer.start(30)  # 约33fps
            self.statusBar.showMessage("已连接摄像头")
        else:
            QMessageBox.warning(self, "错误", "无法连接摄像头")

    def update_frame(self):
        """更新视频帧"""
        if self.video_capture and self.is_video_playing:
            ret, frame = self.video_capture.read()
            if ret:
                # 在这里可以添加视频处理逻辑
                self.processed_image = frame
                self.display_image(self.processed_image)
            else:
                # 视频结束
                self.is_video_playing = False
                self.timer.stop()
                if self.video_capture.get(cv2.CAP_PROP_POS_FRAMES) >= self.video_capture.get(cv2.CAP_PROP_FRAME_COUNT):
                    # 重置视频到开始
                    self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)

    def play_video(self):
        """播放视频"""
        if self.video_capture:
            self.is_video_playing = True
            self.timer.start(30)

    def pause_video(self):
        """暂停视频"""
        self.is_video_playing = False
        self.timer.stop()

    def stop_video(self):
        """停止视频"""
        if self.video_capture:
            self.is_video_playing = False
            self.timer.stop()
            self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)
            ret, frame = self.video_capture.read()
            if ret:
                self.processed_image = frame
                self.display_image(self.processed_image)

    def previous_frame(self):
        """上一帧"""
        if self.video_capture:
            current_pos = self.video_capture.get(cv2.CAP_PROP_POS_FRAMES)
            if current_pos > 1:
                self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, current_pos - 2)
                ret, frame = self.video_capture.read()
                if ret:
                    self.processed_image = frame
                    self.display_image(self.processed_image)

    def next_frame(self):
        """下一帧"""
        if self.video_capture:
            current_pos = self.video_capture.get(cv2.CAP_PROP_POS_FRAMES)
            self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, current_pos)
            ret, frame = self.video_capture.read()
            if ret:
                self.processed_image = frame
                self.display_image(self.processed_image)

    def display_image(self, image):
        """在界面上显示图像"""
        if image is not None:
            # 转换OpenCV图像格式到QImage
            height, width, channel = image.shape
            bytes_per_line = 3 * width
            q_image = QImage(image.data, width, height, bytes_per_line, QImage.Format_RGB888).rgbSwapped()
            self.display_widget.setPixmap(QPixmap.fromImage(q_image).scaled(
                self.display_widget.width(), self.display_widget.height(),
                Qt.KeepAspectRatio, Qt.SmoothTransformation))

    def save_result(self):
        """保存处理后的图像"""
        if self.processed_image is not None:
            file_path, _ = QFileDialog.getSaveFileName(self, "保存图像", "",
                                                       "PNG文件 (*.png);;JPEG文件 (*.jpg *.jpeg);;BMP文件 (*.bmp)")
            if file_path:
                cv2.imwrite(file_path, self.processed_image)
                self.statusBar.showMessage(f"已保存图像: {os.path.basename(file_path)}")

    def update_image_parameters(self):
        """更新图像处理参数"""
        if self.image is not None:
            # 获取参数值
            brightness = self.brightness_slider.value()
            contrast = self.contrast_slider.value() / 100.0 + 1.0  # 转换为1.0-2.0范围
            saturation = self.saturation_slider.value() / 100.0 + 1.0  # 转换为1.0-2.0范围

            # 应用参数
            self.processed_image = self.image.copy()

            # 调整亮度
            if brightness != 0:
                if brightness > 0:
                    shadow = brightness
                    highlight = 255
                else:
                    shadow = 0
                    highlight = 255 + brightness
                alpha_b = (highlight - shadow) / 255
                gamma_b = shadow
                self.processed_image = cv2.addWeighted(self.processed_image, alpha_b,
                                                       self.processed_image, 0, gamma_b)

            # 调整对比度
            if contrast != 1.0:
                f = 131 * (contrast + 127) / (127 * (131 - contrast))
                alpha_c = f
                gamma_c = 127 * (1 - f)
                self.processed_image = cv2.addWeighted(self.processed_image, alpha_c,
                                                       self.processed_image, 0, gamma_c)

            # 调整饱和度 (需要转换到HSV空间)
            if saturation != 1.0:
                hsv = cv2.cvtColor(self.processed_image, cv2.COLOR_BGR2HSV)
                hsv[:, :, 1] = np.clip(hsv[:, :, 1] * saturation, 0, 255).astype(hsv.dtype)
                self.processed_image = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

            self.display_image(self.processed_image)

    def update_face_parameters(self):
        """更新人脸识别参数"""
        # 这里可以添加人脸识别参数更新逻辑
        pass

    def update_shape_parameters(self):
        """更新形状识别参数"""
        # 这里可以添加形状识别参数更新逻辑
        pass

    def rotate_image(self):
        """旋转图像"""
        if self.image is not None:
            # 这里可以实现图像旋转功能
            # 例如：使用QInputDialog获取旋转角度
            # 然后使用cv2.warpAffine进行旋转
            pass

    def scale_image(self):
        """缩放图像"""
        if self.image is not None:
            # 这里可以实现图像缩放功能
            pass

    def crop_image(self):
        """裁剪图像"""
        if self.image is not None:
            # 这里可以实现图像裁剪功能
            pass

    def adjust_color(self):
        """调整色彩"""
        # 色彩调整功能已经通过滑块实现
        pass

    def smooth_image(self):
        """平滑处理图像"""
        if self.image is not None:
            # 应用高斯模糊进行平滑处理
            self.processed_image = cv2.GaussianBlur(self.image, (15, 15), 0)
            self.display_image(self.processed_image)

    def detect_shapes(self):
        """检测图像中的形状"""
        if self.image is not None:
            # 转换为灰度图
            gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

            # 应用阈值
            _, thresh = cv2.threshold(gray, self.shape_threshold.value(), 255, cv2.THRESH_BINARY)

            # 查找轮廓
            contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            # 在原图上绘制轮廓
            self.processed_image = self.image.copy()
            cv2.drawContours(self.processed_image, contours, -1, (0, 255, 0), 2)

            # 识别形状
            for contour in contours:
                # 计算轮廓周长
                perimeter = cv2.arcLength(contour, True)

                # 多边形近似
                approx = cv2.approxPolyDP(contour, 0.04 * perimeter, True)

                # 获取轮廓的边界矩形
                x, y, w, h = cv2.boundingRect(approx)

                # 根据顶点数量识别形状
                if len(approx) == 3:
                    shape = "三角形"
                elif len(approx) == 4:
                    # 检查是否为正方形
                    aspect_ratio = float(w) / h
                    if 0.95 <= aspect_ratio <= 1.05:
                        shape = "正方形"
                    else:
                        shape = "矩形"
                elif len(approx) == 5:
                    shape = "五边形"
                elif len(approx) == 6:
                    shape = "六边形"
                else:
                    # 计算轮廓面积和最小外接圆面积的比率
                    area = cv2.contourArea(contour)
                    ((x, y), radius) = cv2.minEnclosingCircle(contour)
                    circle_area = np.pi * radius * radius
                    if area / circle_area > 0.8:
                        shape = "圆形"
                    else:
                        shape = "多边形"

                # 在形状中心绘制标签
                cv2.putText(self.processed_image, shape, (x, y - 10),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

            self.display_image(self.processed_image)

    def detect_faces(self):
        """检测图像中的人脸"""
        if self.image is not None:
            # 加载人脸检测器
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

            # 转换为灰度图
            gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

            # 检测人脸
            faces = face_cascade.detectMultiScale(gray, 1.1, 4)

            # 在原图上绘制人脸框
            self.processed_image = self.image.copy()
            for (x, y, w, h) in faces:
                cv2.rectangle(self.processed_image, (x, y), (x + w, y + h), (255, 0, 0), 2)

            self.display_image(self.processed_image)

    def recognize_faces(self):
        """识别人脸"""
        if self.image is not None:
            # 加载人脸检测器
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

            # 转换为灰度图
            gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

            # 检测人脸
            faces = face_cascade.detectMultiScale(gray, 1.1, 4)

            # 在原图上绘制人脸框和识别结果
            self.processed_image = self.image.copy()

            # 注意：这是一个简化的人脸识别实现
            # 实际应用中应该使用更复杂的算法如LBPH、Eigenfaces或深度学习模型
            for (x, y, w, h) in faces:
                cv2.rectangle(self.processed_image, (x, y), (x + w, y + h), (255, 0, 0), 2)

                # 提取人脸区域
                face_roi = self.image[y:y + h, x:x + w]

                # 这里应该添加与数据库中人脸比对的逻辑
                # 简化版本：显示"Unknown"
                cv2.putText(self.processed_image, "Unknown", (x, y - 10),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

            self.display_image(self.processed_image)

    def stitch_images(self):
        """图像拼接"""
        # 这里可以实现图像拼接功能
        # 通常需要选择多张图片，然后使用OpenCV的stitcher模块进行拼接
        pass

    def show_about(self):
        """显示关于对话框"""
        QMessageBox.about(self, "关于", "计算机视觉开发平台 v1.0\n\n一个集成图像处理、视频处理和计算机视觉算法的开发平台。")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = CVPlatform()
    window.show()
    sys.exit(app.exec_())
